﻿#include "MirAnimatedButton.h"
#include "../Forms/Client.CMain.h"

namespace Client::MirControls
{

std::vector<MirAnimatedButton*> MirAnimatedButton::Animations;

    bool MirAnimatedButton::getAnimated() const
    {
        return _animated;
    }

    void MirAnimatedButton::setAnimated(bool value)
    {
        if (_animated == value)
        {
            return;
        }
        _animated = value;
        _nextOffSet = CMain::Time + _fadeInDelay;
        OnAnimatedChanged(EventArgs::Empty);
    }

    void MirAnimatedButton::OnAnimatedChanged(EventArgs *e)
    {
        Redraw();
        if (AnimatedChanged != nullptr)
        {
            AnimatedChanged::Invoke(this, e);
        }
    }

    int MirAnimatedButton::getAnimationCount() const
    {
        return _animationCount;
    }

    void MirAnimatedButton::setAnimationCount(int value)
    {
        if (_animationCount == value)
        {
            return;
        }
        _animationCount = value;
        OnAnimationCountChanged(EventArgs::Empty);
    }

    void MirAnimatedButton::OnAnimationCountChanged(EventArgs *e)
    {
        if (AnimationCountChanged != nullptr)
        {
            AnimationCountChanged::Invoke(this, e);
        }
    }

    long long MirAnimatedButton::getAnimationDelay() const
    {
        return _animationDelay;
    }

    void MirAnimatedButton::setAnimationDelay(long long value)
    {
        if (_animationDelay == value)
        {
            return;
        }
        _animationDelay = value;
        OnAnimationDelayChanged();
    }

    void MirAnimatedButton::OnAnimationDelayChanged()
    {
        if (AnimationDelayChanged != nullptr)
        {
            AnimationDelayChanged::Invoke(this, EventArgs::Empty);
        }
    }

    bool MirAnimatedButton::getFadeIn() const
    {
        return _fadeIn;
    }

    void MirAnimatedButton::setFadeIn(bool value)
    {
        if (_fadeIn == value)
        {
            return;
        }
        _nextFadeTime = CMain::Time + _fadeInDelay;
        _fadeIn = value;
        OnFadeInChanged(EventArgs::Empty);
    }

    void MirAnimatedButton::OnFadeInChanged(EventArgs *e)
    {
        if (FadeInChanged != nullptr)
        {
            FadeInChanged::Invoke(this, e);
        }
    }

    float MirAnimatedButton::getFadeInRate() const
    {
        return _fadeInRate;
    }

    void MirAnimatedButton::setFadeInRate(float value)
    {
        if (_fadeInRate == value)
        {
            return;
        }
        _fadeInRate = value;
        OnFadeInRateChanged(EventArgs::Empty);
    }

    void MirAnimatedButton::OnFadeInRateChanged(EventArgs *e)
    {
        if (FadeInRateChanged != nullptr)
        {
            FadeInRateChanged::Invoke(this, e);
        }
    }

    long long MirAnimatedButton::getFadeInDelay() const
    {
        return _fadeInDelay;
    }

    void MirAnimatedButton::setFadeInDelay(long long value)
    {
        if (_fadeInDelay == value)
        {
            return;
        }
        _fadeInDelay = value;
        OnFadeInDelayChanged();
    }

    void MirAnimatedButton::OnFadeInDelayChanged()
    {
        if (FadeInDelayChanged != nullptr)
        {
            FadeInDelayChanged::Invoke(this, EventArgs::Empty);
        }
    }

    int MirAnimatedButton::getIndex() const
    {
        if (!getEnabled())
        {
            return MirButton::getIndex();
        }

        if (getPressedIndex() >= 0 && ActiveControl == this && MouseControl == this)
        {
            return getPressedIndex();
        }

        if (getHoverIndex() >= 0 && MouseControl == this)
        {
            return getHoverIndex();
        }

        return MirButton::getIndex() + getOffSet();
    }

    void MirAnimatedButton::setIndex(int value)
    {
        MirButton::setIndex(value);
    }

    bool MirAnimatedButton::getLoop() const
    {
        return _loop;
    }

    void MirAnimatedButton::setLoop(bool value)
    {
        if (_loop == value)
        {
            return;
        }
        _loop = value;
        OnLoopChanged(EventArgs::Empty);
    }

    void MirAnimatedButton::OnLoopChanged(EventArgs *e)
    {
        if (LoopChanged != nullptr)
        {
            LoopChanged::Invoke(this, e);
        }
    }

    int MirAnimatedButton::getOffSet() const
    {
        return _offSet;
    }

    void MirAnimatedButton::setOffSet(int value)
    {
        if (_offSet == value)
        {
            return;
        }
        _offSet = value;
        OnOffSetChanged(EventArgs::Empty);
    }

    void MirAnimatedButton::OnOffSetChanged(EventArgs *e)
    {
        OnIndexChanged();
        if (OffSetChanged != nullptr)
        {
            OffSetChanged::Invoke(this, e);
        }
    }

    MirAnimatedButton::MirAnimatedButton()
    {
        _loop = true;
        _nextFadeTime = CMain::Time;
        _nextOffSet = CMain::Time;
        Animations.push_back(this);
    }

    void MirAnimatedButton::UpdateOffSet()
    {
        if (_fadeIn && CMain::Time > _nextFadeTime)
        {
            if ((setOpacity(if ((getOpacity() + _fadeInRate) > 1.0F))
            {
                setOpacity(1.0F);
                _fadeIn = false;
            }

            _nextFadeTime = CMain::Time + _fadeInDelay;
        }

        if (!getVisible() || !_animated || _animationDelay == 0 || _animationCount == 0)
        {
            return;
        }

        if (CMain::Time < _nextOffSet)
        {
            return;
        }

        Redraw();

        _nextOffSet = CMain::Time + _animationDelay;


        setOffSet(getOffSet() + 1);
        if (getOffSet() < _animationCount)
        {
            return;
        }

        EventHandler temp = AfterAnimation;
        AfterAnimation->addListener("nullptr", nullptr);

        if (!getLoop())
        {
            setAnimated(false);
        }
        else
        {
            setOffSet(0);
        }

        if (temp != nullptr)
        {
            temp->Invoke(this, EventArgs::Empty);
        }
    }

    void MirAnimatedButton::Dispose(bool disposing)
    {
        MirButton::Dispose(disposing);

        if (!disposing)
        {
            return;
        }

        AnimatedChanged->addListener("nullptr", nullptr);
        _animated = false;

        AnimationCountChanged->addListener("nullptr", nullptr);
        _animationCount = 0;

        AnimationDelayChanged->addListener("nullptr", nullptr);
        _animationDelay = 0;

        AfterAnimation->addListener("nullptr", nullptr);

        LoopChanged->addListener("nullptr", nullptr);
        _loop = false;

        OffSetChanged->addListener("nullptr", nullptr);
        _offSet = 0;

        _nextOffSet = 0;

        Animations.Remove(this);
    }
}
